#ifndef STRAY_GRAPHICS_RENDER_STATE_H
#define STRAY_GRAPHICS_RENDER_STATE_H

#include "../Common.h"

namespace Stray {
namespace Core {
namespace Graphics {

struct BlendState
{
	struct RenderTargetState
	{
		enum Option
		{
			ZERO,
			ONE,
			SRC_COLOR,
			INV_SRC_COLOR,
			SRC_ALPHA,
			INV_SRC_ALPHA,
			DEST_ALPHA,
			INV_DEST_ALPHA,
			DEST_COLOR,
			INV_DEST_COLOR,
			SRC_ALPHA_SAT,
			BLEND_FACTOR,
			INV_BLEND_FACTOR,
		};

		enum Operation
		{
			ADD,
			SUBTRACT,
			REV_SUBTRACT,
			MIN,
			MAX,
		};

		enum Mask
		{
			RED,
			GREEN,
			BLUE,
			ALPHA,
			ALL,
		};

		Stray::Bool blendEnable_;
		Option src_;
		Option dest_;
		Operation operation_;
		Option srcAlpha_;
		Option destAlpha_;
		Operation operationAlpha_;
		Mask writeMask_;
	};

	Stray::Bool alphaToCoverageEnable_;
	Stray::Bool independentBlendEnable_;
	RenderTargetState renderTargetState_[8];

	BlendState()
		:alphaToCoverageEnable_(Stray::B_FALSE)
		,independentBlendEnable_(Stray::B_FALSE)
	{
		for(Uint32 i = 0; i < 8; ++i)
		{
			renderTargetState_[i].blendEnable_ = Stray::B_FALSE;
			renderTargetState_[i].src_ = RenderTargetState::ONE;
			renderTargetState_[i].dest_ = RenderTargetState::ZERO;
			renderTargetState_[i].operation_ = RenderTargetState::ADD;
			renderTargetState_[i].srcAlpha_ = RenderTargetState::ONE;
			renderTargetState_[i].destAlpha_ = RenderTargetState::ZERO;
			renderTargetState_[i].operationAlpha_ = RenderTargetState::ADD;
			renderTargetState_[i].writeMask_ = RenderTargetState::ALL;
		}
	}
};

struct DepthStencilState
{
	enum Operation
	{
		KEEP,
		ZERO,
		REPLACE,
		INCR_SAT,
		DECR_SAT,
		INVERT,
		INCR,
		DECR,
	};

	enum CompFunc
	{
		NEVER,
		LESS,
		EQUAL,
		LESS_EQUAL,
		GREATER,
		NOT_EWUAL,
		GREATER_EQUAL,
		ALWAYS,
	};

	Operation onStencilFail_;
	Operation onStencilPassDepthFail_;
	Operation onStencilDepthPass_;
	CompFunc compFunc_;

	DepthStencilState()
		:onStencilFail_(KEEP)
		,onStencilPassDepthFail_(KEEP)
		,onStencilDepthPass_(KEEP)
		,compFunc_(ALWAYS)
	{
	}
};

struct RasterizerState
{
	enum FillMode
	{
		WIREFRAME,
		SOLID,
	};

	enum CullMode
	{
		NONE,
		FRONT,
		BACK,
	};
	
	FillMode fillMode_;
	CullMode cullMode_;
	Bool frontCCW_;
	Stray::Int32 depthBias_;
	Stray::Float32 depthClamp_;
	Stray::Float32 slopeScaledDepthBias_;
	Stray::Bool depthClipEnable_;
	Stray::Bool scissorEnable_;
	Stray::Bool multisampleEnable_;
	Stray::Bool antialiasedLineEnable_;

	RasterizerState()
		:fillMode_(SOLID)
		,cullMode_(BACK)
		,frontCCW_(Stray::B_FALSE)
		,depthBias_(0)
		,depthClamp_(0.f)
		,slopeScaledDepthBias_(0.f)
		,depthClipEnable_(Stray::B_TRUE)
		,scissorEnable_(Stray::B_FALSE)
		,multisampleEnable_(Stray::B_FALSE)
		,antialiasedLineEnable_(Stray::B_FALSE)
	{
	}
};

struct SamplerState
{
	enum FilterType
	{
		POINT,
		LINEAR,
	};

	enum TextureAddressMode
	{
		WRAP,
		MIRROR,
		CLAMP,
		BORDER,
		MIRROR_ONCE,
	};

	FilterType minFilter_;
	FilterType magFilter_;
	FilterType mipFilter_;
	Stray::Bool useAnisotropicFilter_;
	Stray::Uint8 maxAnisotropy_;
	TextureAddressMode uAddMode_;
	TextureAddressMode vAddMode_;
	TextureAddressMode wAddMode_;
	Stray::Float32 mipLODBias_;
	Stray::Float32 borderColor_[4];
	Stray::Float32 minLOD_;
	Stray::Float32 maxLOD_;

	SamplerState()
		:minFilter_(LINEAR)
		,magFilter_(LINEAR)
		,mipFilter_(LINEAR)
		,useAnisotropicFilter_(Stray::B_FALSE)
		,maxAnisotropy_(16)
		,uAddMode_(CLAMP)
		,vAddMode_(CLAMP)
		,wAddMode_(CLAMP)
		,mipLODBias_(0)
		,minLOD_(-FLT_MAX)
		,maxLOD_(FLT_MAX)
	{
		for(Uint32 i = 0; i < 4; ++i)
		{
			borderColor_[i] = 0;
		}
	}
};

}
}
}

#endif